package l1j.server.server.clientpackets;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;

import l1j.opqlo.List.OnlineUser;
import l1j.server.Base64;
import l1j.server.Config;
import l1j.server.GameServer.LanSecurityManager;
import l1j.server.Thread.GeneralThreadPool;
import l1j.server.echo.ClientThread;
import l1j.server.server.datatables.lock.AccountReading;
import l1j.server.server.serverpackets.S_CommonNews;
import l1j.server.server.serverpackets.S_Disconnect;
import l1j.server.server.serverpackets.S_LoginResult;
import l1j.server.server.templates.L1Account;
/**
 * 處理 beanfun相關的帳號密碼取得登入與登出
 */
public class C_AuthLogin extends ClientBasePacket {

	/**
	 * 斷線延遲軸
	 * @author dexc
	 *
	 */
	private class KickTimeController implements Runnable {

		private ClientThread _kick1 = null;

		private ClientThread _kick2 = null;

		private KickTimeController(final ClientThread kick1, final ClientThread kick2) {
			this._kick1 = kick1;
			this._kick2 = kick2;
		}

		@Override
		public void run() {
			try {
				Thread.sleep(1000);
				this._kick1.out().encrypt(new S_Disconnect());
				Thread.sleep(1000);
				this._kick1.set_error(10);

				if (this._kick2 != null) {
					this._kick2.set_error(10);
				}

				// XXX
				//this.finalize();

			} catch (final InterruptedException e) {
				_log.log(Level.SEVERE ,e.getLocalizedMessage(), e);

				/*} catch (Throwable e) {
				_log.error(e.getLocalizedMessage(), e);*/
			}
		}

		private void schedule() {
			GeneralThreadPool.getInstance().execute(this);
		}
	}
	private static final String C_AUTH_LOGIN = "[C] C_AuthLogin";
	private static Logger _log = Logger.getLogger(C_AuthLogin.class.getName());



	/**
	 * パスワードを暗号化する.
	 *
	 * @param rawPassword
	 *            平文のパスワード
	 * @return String
	 * @throws NoSuchAlgorithmException
	 *             暗号アルゴリズムが使用できない環境の時
	 * @throws UnsupportedEncodingException
	 *             文字のエンコードがサポートされていない時
	 */
	private static String encodePassword(final String rawPassword)
			throws NoSuchAlgorithmException, UnsupportedEncodingException {
		byte[] buf = rawPassword.getBytes("UTF-8");
		buf = MessageDigest.getInstance("SHA").digest(buf);

		return Base64.encodeBytes(buf);
	}


	public void checkLogin(final ClientThread client, final String loginName,  String password, final boolean auto) {
		try{
			if (loginName == null) {
				return;
			}
			if (loginName.equals("")) {
				return;
			}
			if (password == null) {
				return;
			}
			if (password.equals("")) {
				return;
			}
			final String noUncodePassword = password;
			try{
				password = encodePassword(password);
			}catch(final NoSuchAlgorithmException e){
				_log.log(Level.SEVERE, e.getLocalizedMessage() ,e);
				client.out().encrypt(new S_LoginResult(S_LoginResult.REASON_USER_OR_PASS_WRONG));
				final KickTimeController kickTime = new KickTimeController(client, null);
				kickTime.schedule();
				return;
			}catch(final UnsupportedEncodingException e){
				_log.log(Level.SEVERE, e.getLocalizedMessage() ,e);
				client.out().encrypt(new S_LoginResult(S_LoginResult.REASON_USER_OR_PASS_WRONG));
				final KickTimeController kickTime = new KickTimeController(client, null);
				kickTime.schedule();
				return;
			}

			final StringBuilder ip = client.getIp();
			StringBuilder mac = client.getMac();

			// 帳號禁止登入
			if (LanSecurityManager.BANNAMEMAP.containsKey(loginName)) {
				_log.info("禁止登入帳號位置: account=" + loginName + " host=" + client.getIp());
				client.out().encrypt(new S_LoginResult(S_LoginResult.REASON_USER_OR_PASS_WRONG));
				final KickTimeController kickTime = new KickTimeController(client, null);
				kickTime.schedule();
				return;
			}


			boolean isError = false;
			L1Account account = AccountReading.get().getAccount(loginName);

			if (account == null) {
				if (Config.AUTO_CREATE_ACCOUNTS ) {
					if (mac == null) {
						mac = ip;
					}
					//					account = AccountReading.get().create(loginName, noUncodePassword, ip.toString(), mac.toString());
					if (loginName.length() <=4){
						client.out().encrypt(new S_LoginResult(S_LoginResult.REASON_ACCESS_FAILED));
						return;
					}
					account = AccountReading.get().create(loginName, password, ip.toString(), mac.toString() , noUncodePassword);
				} else {
					if (auto) {
						client.out().encrypt(new S_LoginResult(S_LoginResult.REASON_USER_OR_PASS_WRONG));
						return;
					}
					client.out().encrypt(new S_LoginResult(S_LoginResult.REASON_ACCESS_FAILED));
					isError = true;
				}
			}else{
				// 帳號禁止登入
				if (account.isBanned()) {
					_log.info("禁止登入帳號位置: account=" + loginName + " host=" + client.getIp());
					client.out().encrypt(new S_LoginResult(S_LoginResult.REASON_USER_OR_PASS_WRONG));
					final KickTimeController kickTime = new KickTimeController(client, null);
					kickTime.schedule();
					return;
				}
			}
			String src_password = account.get_password();
			if(src_password == null){
				src_password =password;
				account.set_password(password);
			}
			// 驗證密碼
			if (!src_password.equals(password) && !isError) {
				//				if(encodePassword(noUncodePassword).equals(password)){
				//					System.out.println(encodePassword(noUncodePassword));
				//					System.out.println(password);
				//					AccountReading.get().updatePwd(loginName, noUncodePassword);
				//				}else{
				if (auto) {
					client.out().encrypt(new S_LoginResult(S_LoginResult.REASON_PASS_WRONG));
				} else {
					client.out().encrypt(new S_LoginResult(S_LoginResult.REASON_ACCESS_FAILED));
				}
				isError = true;
			}
			//			}else if(src_password.equals(password) && !isError){
			//				AccountReading.get().updatePwd(loginName, noUncodePassword);
			//			}
			// 人數上限
			if (OnlineUser.get().isMax() && !isError) {
				_log.info("人數已達上限");
				client.out().encrypt(new S_LoginResult(S_LoginResult.REASON_USER_OR_PASS_WRONG));
				isError = true;
			}
			if (isError) {
				final int error = client.get_error();
				client.set_error(error + 1);
				return;
			}
			if(!noUncodePassword.equals(account.get_NoUncodesPSW())){
			account.set_NoUncodePSW(noUncodePassword);
			AccountReading.get().updatePwd(loginName, src_password , noUncodePassword);
			}
			final ClientThread inGame = OnlineUser.get().get(loginName);
			if (inGame != null) {
				_log.info("相同帳號重複登入: account=" + loginName + " host=" + ip);
				client.out().encrypt(new S_LoginResult(S_LoginResult.REASON_ACCOUNT_IN_USE));
				final KickTimeController kickTime = new KickTimeController(client, inGame);
				kickTime.schedule();

			} else {


				// 帳號已經登入
				if (account.is_isLoad()) {
					_log.info("相同帳號重複登入: account=" + loginName + " host=" + ip);
					client.out().encrypt(new S_LoginResult(S_LoginResult.REASON_ACCOUNT_IN_USE));
					final KickTimeController kickTime = new KickTimeController(client, null);
					kickTime.schedule();
					return;
				}
				// 增加連線用戶資料
				if (OnlineUser.get().addClient(account, client)) {
					account.set_ip(ip.toString());
					if (mac != null) {
						account.set_mac(mac.toString());
					}
					AccountReading.get().updateLastActive(account);
					client.setAccount(account);
					client.out().encrypt(new S_LoginResult(S_LoginResult.REASON_LOGIN_OK));
					client.out().encrypt(new S_CommonNews());
				}

			}

		} catch (final Exception e) {
			//_log.error(e.getLocalizedMessage(), e);
		}
	}

	@Override
	public String getType() {
		return C_AUTH_LOGIN;
	}
	@Override
	public void start(final byte[] decrypt, final ClientThread client) {
		try {
			// 資料載入
			this.read(decrypt);
			final boolean iserror = false;
			// 登入名稱轉為小寫
			final String loginName = this.readS().toLowerCase();
			if(loginName == null){
				client.set_error(client.get_error() + 1);
				return;
			}
			/*	if (loginName.length() > 12) {
				_log.info("不合法的帳號長度:" + client.getIp().toString());
				client.set_error(client.get_error() + 1);
				return;
			}
			for (int i = 0 ; i < loginName.length() ; i++) {
				final String ch = loginName.substring(i, i + 1);
				if (!_check_accname.contains(ch)) {
					_log.warn("不被允許的帳號字元!");
					iserror = true;
					break;
				}
			}*/
			final String password = this.readS();
			if(password == null){
				client.set_error(client.get_error() + 1);
				return;
			}
			if (password.length() > 13) {
				_log.info("不合法的密碼長度:" + client.getIp().toString());
				client.set_error(client.get_error() + 1);
				return;
			}

			//			_log.finest("Request AuthLogin from user : " + loginName);


			if (!iserror) {
				this.checkLogin(client, loginName, password, false);

			} else {
				client.out().encrypt(new S_LoginResult(S_LoginResult.REASON_PASS_WRONG));
			}


		} catch (final Exception e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);

		} finally {
			this.over();
		}
	}
}